// Copyright 2022 Huawei Cloud Computing Technology Co., Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import logger from './Logger';
const Logger = logger;

const FRAME_TYPE_MAP = {
  2: 'Audio',
  3: 'Video',
  8: 'HeartBeat',
  7: 'CmdControl',
  9: 'Orientation',
  10: 'Snapshot',
  14: 'KeyboardInput',
  60: 'PhoneControl',
  21: 'Camera',
  22: 'MicroPhone',
  23: 'Sensor',
  24: 'GpsLocation'
};
const INVALID_FRAME_TYPE = 'Invalid';
// 限制数据包缓存的长度，避免过多占用资源
const MAX_PKG_NUMBER = 300;
const PACKAGE_HEADER_LENGTH = 8;

class FrameParser {
  constructor(supportAudio) {
    this.pkgList = {
      Audio: [],
      Video: [],
      HeartBeat: [],
      CmdControl: [],
      Orientation: [],
      KeyboardInput: [],
      PhoneControl: [],
      Camera: [],
      MicroPhone: [],
      Channel: [],
      Sensor: [],
      GpsLocation: [],
      Snapshot: []
    };
    this.lastBuf = null;
    // 完整数据包length，含header
    this.completePkgLen = 0;
    this.supportAudio = supportAudio;
  }

  getSizeFromPackage(typeBuf, pkgStart) {
    pkgStart = pkgStart || 0;
    if (typeBuf.length < pkgStart + PACKAGE_HEADER_LENGTH) {
      Logger.debug('The package is invalid.');
      return 0;
    }

    return (
      (typeBuf[pkgStart + 4] << 24) |
      (typeBuf[pkgStart + 5] << 16) |
      (typeBuf[pkgStart + 6] << 8) |
      typeBuf[pkgStart + 7]
    );
  }

  getTypeFromPackage(typeBuf, pkgStart) {
    pkgStart = pkgStart || 0;
    if (typeBuf.length < pkgStart + PACKAGE_HEADER_LENGTH) {
      Logger.debug('The package is invalid.');
      return INVALID_FRAME_TYPE;
    }

    return FRAME_TYPE_MAP[typeBuf[pkgStart + 3]] || INVALID_FRAME_TYPE;
  }

  getSubTypeBuffer(typeBuf, start, end) {
    end = end || typeBuf.length;
    const subBuf = typeBuf.subarray(start, end);
    const newBuf = new Uint8Array(subBuf.length);
    newBuf.set(subBuf);
    return newBuf;
  }

  readPackage(recvdBuf) {
    if (!recvdBuf || recvdBuf.byteLength < 1) {
      return;
    }

    // 已经接收到的数据（包含本次和之前数据包剩下的）
    let allDataBuf = null;
    let recvdTypeBuf = new Uint8Array(recvdBuf);
    if (this.lastBuf) {
      allDataBuf = new Uint8Array(this.lastBuf.length + recvdBuf.byteLength);
      allDataBuf.set(this.lastBuf);
      allDataBuf.set(recvdTypeBuf, this.lastBuf.length);
    } else {
      // 忽略心跳响应包
      const pkgType = this.getTypeFromPackage(recvdTypeBuf);
      if (
        pkgType === INVALID_FRAME_TYPE ||
        (!this.supportAudio && pkgType === FRAME_TYPE_MAP[2]) /* Audio */
      ) {
        recvdTypeBuf = null;
        return;
      }

      allDataBuf = recvdTypeBuf;
    }

    // 需要的组成一整包的数据，包含header
    if (!this.completePkgLen) {
      this.completePkgLen = this.getSizeFromPackage(allDataBuf) + PACKAGE_HEADER_LENGTH;
    }

    // 已有数据和需要的数据length比较
    if (allDataBuf.length === this.completePkgLen) {
      let type = this.getTypeFromPackage(allDataBuf);
      this.pushPackage(type, this.getSubTypeBuffer(allDataBuf, PACKAGE_HEADER_LENGTH));
      this.lastBuf = null;
      this.completePkgLen = 0;
    } else if (allDataBuf.length < this.completePkgLen) {
      this.lastBuf = allDataBuf;
    } else {
      let pkgStart = 0;
      let pkgLen = 0;
      const allDataLen = allDataBuf.length;
      while (allDataLen - pkgStart >= PACKAGE_HEADER_LENGTH) {
        pkgLen = this.getSizeFromPackage(allDataBuf, pkgStart) + PACKAGE_HEADER_LENGTH;
        if (allDataLen - pkgStart >= pkgLen) {
          let type = this.getTypeFromPackage(allDataBuf, pkgStart);
          this.pushPackage(
            type,
            this.getSubTypeBuffer(allDataBuf, pkgStart + PACKAGE_HEADER_LENGTH, pkgStart + pkgLen)
          );
          pkgStart += pkgLen;
        } else {
          break;
        }
      }

      // 仍剩下不完整包的数据，存储至lastBuf
      if (allDataLen > pkgStart) {
        this.lastBuf = this.getSubTypeBuffer(allDataBuf, pkgStart);
      }

      this.completePkgLen = 0;
    }
  }

  pushPackage(type, pkg) {
    if (!this.pkgList[type]) {
      return;
    }

    if (this.pkgList[type].length >= MAX_PKG_NUMBER) {
      this.pkgList[type] = [];
    }

    this.pkgList[type].push(pkg);
  }

  shiftPackage(type) {
    return this.pkgList[type] && this.pkgList[type].shift();
  }

  clearPackageCache(type) {
    this.pkgList[type] && (this.pkgList[type] = []);
  }

  getPackageCacheNum(type) {
    return this.pkgList[type] && this.pkgList[type].length;
  }
}

export default FrameParser;
